package com.leyou.auth.service;

import com.leyou.auth.config.JwtProperties;
import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.user.clent.UserClient;
import com.leyou.user.dto.UserDTO;
import com.netflix.client.http.HttpResponse;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author syf
 * @version 1.0
 * @date 2019/08/14 10:23
 * @Description TODO:登陆代码实现
 */
@Service
public class AuthService {

    @Autowired
    private UserClient userClient;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String USER_ROLE="USER_ROLE";

    public void login(String username, String password, HttpServletResponse response) {
        try {
            //验证用户名和密码
            UserDTO userDTO = userClient.findByUsernameAndPassword(username, password);
            if (userDTO==null){
                //无效的用户名和密码
                throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
            }
            //生成token
            UserInfo userInfo = new UserInfo(userDTO.getId(), userDTO.getUsername(), USER_ROLE);
            String token = JwtUtils.generateTokenExpireInMinutes(userInfo, jwtProperties.getPrivateKey(),
                                    jwtProperties.getUser().getExpire());
            //写入token

            new CookieUtils.CookieBuilder()
                    .response(response) // response,用于写cookie
                    .httpOnly(true) // 保证安全防止XSS攻击，不允许JS操作cookie
                    .domain(jwtProperties.getUser().getCookieDomain()) // 设置domain
                    .name(jwtProperties.getUser().getCookieName()).value(token) // 设置cookie名称和值
                    .build();// 写cookie
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }




    }

    //验证用户信息
    public UserInfo verify(HttpServletRequest request, HttpServletResponse response) {
        try {
            //从cookie中获取token
            String token = CookieUtils.getCookieValue(request, jwtProperties.getUser().getCookieName());
            //验证token是否正确，超时就报错
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey(), UserInfo.class);

            /////修改登录校验逻辑
            //获取token的id
            String id = payload.getId();
            //查看token是否在黑名单中
            Boolean boo = redisTemplate.hasKey(id);
            if (boo != null && boo){
                //抛出异常，证明token无效，直接返回401
                //登陆失效或登陆失败
                throw new LyException(ExceptionEnum.UNAUTHORIZED);
            }

            //获取UserINfo信息
            UserInfo userInfo = payload.getUserInfo();
            //查看过期时间
            Date expiration = payload.getExpiration();
            //在过期时间前设置一个续约token时间:15分钟
            DateTime dateTime = new DateTime(expiration.getTime()).minusMinutes(15);
            //续约：当续约时间在当前时间之前就要续约
            if (dateTime.isBefore(System.currentTimeMillis())){
                //生成token
                String reMainToken = JwtUtils.generateTokenExpireInMinutes(userInfo, jwtProperties.getPrivateKey(),
                        jwtProperties.getUser().getExpire());
                //写入token

                new CookieUtils.CookieBuilder()
                        .response(response) // response,用于写cookie
                        .httpOnly(true) // 保证安全防止XSS攻击，不允许JS操作cookie
                        .domain(jwtProperties.getUser().getCookieDomain()) // 设置domain
                        .name(jwtProperties.getUser().getCookieName()).value(reMainToken) // 设置cookie名称和值
                        .build();// 写cookie
            }
            return userInfo;
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }

    }

    //退出登陆
    public void logout(String token,HttpServletResponse response) {
        try {
            //校验token是否正确，如果不正确就不用做了
            Payload<Object> payload = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey());
            //获取id和有效期剩余时长
            String id = payload.getId();
            long time = payload.getExpiration().getTime() - System.currentTimeMillis();
            //写入redis，剩余时间超过5秒以上才写，存入redis黑名单
            if (time > 5000) {
                redisTemplate.opsForValue().set(id, "1", time, TimeUnit.MILLISECONDS);
            }
            //删除cookie
            CookieUtils.deleteCookie(jwtProperties.getUser().getCookieName(), jwtProperties.getUser().getCookieDomain(), response);

        } catch (Exception e) {
            //解析token异常
            throw new LyException(ExceptionEnum.TOKEN_ERROR);
        }
    }
}
